const axios = require('axios')
const { Op } = require('sequelize')
const redisClient = require('../config/redis')
const logger = require('../utils/logger')
const { NotificationLog } = require('../models')

class WechatTemplateService {
  constructor() {
    this.appId = process.env.WECHAT_APPID
    this.appSecret = process.env.WECHAT_APP_SECRET
    this.accessTokenKey = 'wechat_access_token'
    this.accessTokenExpiry = 7000 // 微信access_token有效期7200秒，提前200秒刷新
    
    // 模板消息配置
    this.templates = {
      points_earned: {
        templateId: process.env.WECHAT_TEMPLATE_POINTS_EARNED || 'template_001',
        title: '积分到账通知'
      },
      points_consumed: {
        templateId: process.env.WECHAT_TEMPLATE_POINTS_CONSUMED || 'template_002',
        title: '积分消费通知'
      },
      points_expire_warning: {
        templateId: process.env.WECHAT_TEMPLATE_POINTS_EXPIRE || 'template_003',
        title: '积分过期提醒'
      },
      order_status_update: {
        templateId: process.env.WECHAT_TEMPLATE_ORDER_UPDATE || 'template_004',
        title: '订单状态更新'
      },
      member_upgrade: {
        templateId: process.env.WECHAT_TEMPLATE_MEMBER_UPGRADE || 'template_005',
        title: '会员等级提升'
      }
    }
  }

  /**
   * 获取微信access_token
   * @returns {Promise<string>} access_token
   */
  async getAccessToken() {
    try {
      // 先从缓存获取
      const cachedToken = await redisClient.get(this.accessTokenKey)
      if (cachedToken) {
        return cachedToken
      }

      // 从微信API获取新token
      const response = await axios.get('https://api.weixin.qq.com/cgi-bin/token', {
        params: {
          grant_type: 'client_credential',
          appid: this.appId,
          secret: this.appSecret
        }
      })

      if (response.data.access_token) {
        const accessToken = response.data.access_token
        // 缓存token
        await redisClient.setEx(this.accessTokenKey, this.accessTokenExpiry, accessToken)
        logger.info('微信access_token获取成功')
        return accessToken
      } else {
        throw new Error(`获取access_token失败: ${response.data.errmsg}`)
      }
    } catch (error) {
      logger.error('获取微信access_token失败:', error)
      throw error
    }
  }

  /**
   * 发送模板消息
   * @param {string} openid - 用户openid
   * @param {string} templateType - 模板类型
   * @param {Object} data - 模板数据
   * @param {Object} options - 其他选项
   * @returns {Promise<Object>} 发送结果
   */
  async sendTemplateMessage(openid, templateType, data, options = {}) {
    try {
      const template = this.templates[templateType]
      if (!template) {
        throw new Error(`不支持的模板类型: ${templateType}`)
      }

      const accessToken = await this.getAccessToken()
      
      // 构建模板消息数据
      const messageData = {
        touser: openid,
        template_id: template.templateId,
        url: options.url || '',
        miniprogram: options.miniprogram || null,
        data: this.formatTemplateData(data)
      }

      // 记录发送日志
      const logData = {
        userId: options.userId,
        messageId: options.messageId,
        type: 'wechat_template',
        platform: 'miniprogram',
        templateId: template.templateId,
        recipient: openid,
        title: template.title,
        content: JSON.stringify(data),
        templateData: messageData,
        status: 'pending'
      }
      
      const notificationLog = await NotificationLog.create(logData)

      try {
        // 发送模板消息
        const response = await axios.post(
          `https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=${accessToken}`,
          messageData
        )

        if (response.data.errcode === 0) {
          // 发送成功
          await notificationLog.update({
            status: 'sent',
            sentAt: new Date()
          })
          
          logger.info(`微信模板消息发送成功: ${openid}, msgid: ${response.data.msgid}`)
          return {
            success: true,
            msgid: response.data.msgid,
            logId: notificationLog.id
          }
        } else {
          // 发送失败
          await notificationLog.update({
            status: 'failed',
            errorMessage: `${response.data.errcode}: ${response.data.errmsg}`
          })
          
          throw new Error(`微信模板消息发送失败: ${response.data.errmsg}`)
        }
      } catch (sendError) {
        // 更新日志状态
        await notificationLog.update({
          status: 'failed',
          errorMessage: sendError.message
        })
        throw sendError
      }
    } catch (error) {
      logger.error('发送微信模板消息失败:', error)
      throw error
    }
  }

  /**
   * 格式化模板数据
   * @param {Object} data - 原始数据
   * @returns {Object} 格式化后的数据
   */
  formatTemplateData(data) {
    const formatted = {}
    
    for (const [key, value] of Object.entries(data)) {
      formatted[key] = {
        value: value,
        color: data[`${key}_color`] || '#173177'
      }
    }
    
    return formatted
  }

  /**
   * 发送积分到账通知
   * @param {string} openid - 用户openid
   * @param {Object} data - 通知数据
   * @returns {Promise<Object>} 发送结果
   */
  async sendPointsEarnedNotification(openid, data) {
    const templateData = {
      first: `恭喜您获得${data.points}积分！`,
      keyword1: data.source || '观看广告',
      keyword2: data.points,
      keyword3: data.balance,
      keyword4: new Date().toLocaleString('zh-CN'),
      remark: '感谢您的使用，继续加油哦！'
    }

    return await this.sendTemplateMessage(openid, 'points_earned', templateData, {
      userId: data.userId,
      messageId: data.messageId,
      miniprogram: {
        appid: this.appId,
        pagepath: 'pages/points/index'
      }
    })
  }

  /**
   * 发送积分消费通知
   * @param {string} openid - 用户openid
   * @param {Object} data - 通知数据
   * @returns {Promise<Object>} 发送结果
   */
  async sendPointsConsumedNotification(openid, data) {
    const templateData = {
      first: `您已成功消费${data.points}积分`,
      keyword1: data.orderNo || '',
      keyword2: data.points,
      keyword3: data.balance,
      keyword4: new Date().toLocaleString('zh-CN'),
      remark: '订单处理中，请耐心等待'
    }

    return await this.sendTemplateMessage(openid, 'points_consumed', templateData, {
      userId: data.userId,
      messageId: data.messageId,
      miniprogram: {
        appid: this.appId,
        pagepath: `pages/orders/detail?id=${data.orderId}`
      }
    })
  }

  /**
   * 发送积分过期提醒
   * @param {string} openid - 用户openid
   * @param {Object} data - 通知数据
   * @returns {Promise<Object>} 发送结果
   */
  async sendPointsExpireWarning(openid, data) {
    const templateData = {
      first: '您有积分即将过期，请及时使用',
      keyword1: data.expiringPoints,
      keyword2: data.expireDate,
      keyword3: data.currentBalance,
      remark: '点击查看详情，立即使用积分兑换商品'
    }

    return await this.sendTemplateMessage(openid, 'points_expire_warning', templateData, {
      userId: data.userId,
      messageId: data.messageId,
      miniprogram: {
        appid: this.appId,
        pagepath: 'pages/products/index'
      }
    })
  }

  /**
   * 发送订单状态更新通知
   * @param {string} openid - 用户openid
   * @param {Object} data - 通知数据
   * @returns {Promise<Object>} 发送结果
   */
  async sendOrderStatusUpdate(openid, data) {
    const statusMap = {
      processing: '处理中',
      completed: '已完成',
      cancelled: '已取消'
    }

    const templateData = {
      first: '您的订单状态已更新',
      keyword1: data.orderNo,
      keyword2: statusMap[data.status] || data.status,
      keyword3: new Date().toLocaleString('zh-CN'),
      remark: data.status === 'completed' ? '订单已完成，感谢您的使用！' : '如有疑问请联系客服'
    }

    return await this.sendTemplateMessage(openid, 'order_status_update', templateData, {
      userId: data.userId,
      messageId: data.messageId,
      miniprogram: {
        appid: this.appId,
        pagepath: `pages/orders/detail?id=${data.orderId}`
      }
    })
  }

  /**
   * 发送会员升级通知
   * @param {string} openid - 用户openid
   * @param {Object} data - 通知数据
   * @returns {Promise<Object>} 发送结果
   */
  async sendMemberUpgradeNotification(openid, data) {
    const levelMap = {
      silver: '白银会员',
      gold: '黄金会员',
      diamond: '钻石会员'
    }

    const templateData = {
      first: '恭喜您的会员等级提升了！',
      keyword1: levelMap[data.newLevel] || data.newLevel,
      keyword2: data.totalPoints,
      keyword3: new Date().toLocaleString('zh-CN'),
      remark: '享受更多会员权益，立即查看详情'
    }

    return await this.sendTemplateMessage(openid, 'member_upgrade', templateData, {
      userId: data.userId,
      messageId: data.messageId,
      miniprogram: {
        appid: this.appId,
        pagepath: 'pages/member/index'
      }
    })
  }

  /**
   * 批量发送模板消息
   * @param {Array} messages - 消息列表
   * @returns {Promise<Array>} 发送结果列表
   */
  async sendBatchTemplateMessages(messages) {
    const results = []
    
    for (const message of messages) {
      try {
        const result = await this.sendTemplateMessage(
          message.openid,
          message.templateType,
          message.data,
          message.options
        )
        results.push({ success: true, ...result })
      } catch (error) {
        results.push({ 
          success: false, 
          error: error.message,
          openid: message.openid 
        })
      }
    }
    
    return results
  }

  /**
   * 重试失败的通知
   * @param {number} logId - 通知日志ID
   * @returns {Promise<Object>} 重试结果
   */
  async retryFailedNotification(logId) {
    try {
      const log = await NotificationLog.findByPk(logId)
      if (!log || log.status !== 'failed') {
        throw new Error('通知日志不存在或状态不正确')
      }

      if (log.retryCount >= 3) {
        throw new Error('重试次数已达上限')
      }

      // 更新重试状态
      await log.update({
        status: 'retry',
        retryCount: log.retryCount + 1
      })

      // 重新发送
      const templateData = log.templateData
      const response = await axios.post(
        `https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=${await this.getAccessToken()}`,
        templateData
      )

      if (response.data.errcode === 0) {
        await log.update({
          status: 'sent',
          sentAt: new Date()
        })
        return { success: true, msgid: response.data.msgid }
      } else {
        await log.update({
          status: 'failed',
          errorMessage: `${response.data.errcode}: ${response.data.errmsg}`
        })
        throw new Error(`重试发送失败: ${response.data.errmsg}`)
      }
    } catch (error) {
      logger.error('重试微信模板消息失败:', error)
      throw error
    }
  }

  /**
   * 获取发送统计
   * @param {Object} options - 查询选项
   * @returns {Promise<Object>} 统计结果
   */
  async getSendStatistics(options = {}) {
    try {
      const { startDate, endDate, userId, templateType } = options
      
      const whereClause = {
        type: 'wechat_template'
      }
      
      if (startDate && endDate) {
        whereClause.createdAt = {
          [Op.between]: [startDate, endDate]
        }
      }
      
      if (userId) {
        whereClause.userId = userId
      }
      
      if (templateType && this.templates[templateType]) {
        whereClause.templateId = this.templates[templateType].templateId
      }

      const [total, sent, failed, pending] = await Promise.all([
        NotificationLog.count({ where: whereClause }),
        NotificationLog.count({ where: { ...whereClause, status: 'sent' } }),
        NotificationLog.count({ where: { ...whereClause, status: 'failed' } }),
        NotificationLog.count({ where: { ...whereClause, status: 'pending' } })
      ])

      return {
        total,
        sent,
        failed,
        pending,
        successRate: total > 0 ? ((sent / total) * 100).toFixed(2) : 0
      }
    } catch (error) {
      logger.error('获取发送统计失败:', error)
      throw error
    }
  }
}

module.exports = new WechatTemplateService()